Skip to content

fix(aicore): make content filter misconfiguration visible - #458

Merged
ricardosrib merged 2 commits into
mainfrom
fix/aicore-content-filter-fail-open
Nov 11, 2026
Merged

ricardosrib merged 2 commits into
mainfrom
fix/aicore-content-filter-fail-open

Conversation

@ricardosrib

Copy link
Copy Markdown
Contributor

Description

Fixes a silent fail-open in the AI Core content filtering integration. When filtering was misconfigured or never set up, requests were sent unfiltered with no warning, no exception, and no way to enforce fail-closed behaviour.

This PR makes misconfiguration visible: a logger.warning is emitted whenever a request would proceed without filtering.

Also added an opt-in strict mode (set_filtering(strict=True) or AICORE_FILTER_STRICT=true), which raises ContentFilteringNotConfiguredError instead of sending an unfiltered request. Intentional opt-outs via disable_filtering() or AICORE_FILTER_ENABLED=false remain silent.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Code refactoring
  • Dependency update

How to Test

  1. Default (fail-open with warning): call completion() without first calling set_aicore_config() or set_filtering(); confirm a logging.WARNING containing "never configured" is emitted exactly once and the call proceeds.
  2. Strict mode via env: set AICORE_FILTER_STRICT=true and repeat step 1; confirm ContentFilteringNotConfiguredError is raised before the network call is made.
  3. Strict mode programmatic: call set_filtering(ContentFiltering(), strict=True) (empty config) then a stubbed completion(); confirm ContentFilteringNotConfiguredError is raised.
  4. Intentional opt-out stays silent: call disable_filtering() then completion(); confirm no warning is logged.
  5. Run the test suite: pytest tests/aicore -q — all tests should pass.

Checklist

  • I have read the Contributing Guidelines
  • I have verified that my changes solve the issue
  • I have added/updated automated tests to cover my changes
  • All tests pass locally
  • I have verified that my code follows the Code Guidelines
  • I have updated documentation (if applicable)
  • I have added type hints for all public APIs
  • My code does not contain sensitive information (credentials, tokens, etc.)
  • I have followed Conventional Commits for commit messages
  • (Security-sensitive changes only) I have run /security-review and addressed all ❌ findings

Additional Notes

Collateral formatting changes

Running ruff format . as part of CI prep reformatted inline comments and wrapped long lines in several unrelated user guides and docs/GUIDELINES.md. These are whitespace-only changes with no semantic content.

- Add ContentFilteringNotConfiguredError for fail-closed (strict) mode
- Emit logger.warning on both fail-open branches in transform_request
- Add _assert_filtering_ready() pre-flight guard in completion()/acompletion()
- Expose strict mode via AICORE_FILTER_STRICT env var and set_filtering(strict=)
- Export new exception from aicore and filtering packages
- Document strict mode and new env var in user-guide.md
@ricardosrib
ricardosrib requested a review from a team as a code owner November 6, 2026 18:19

@ricardosrib ricardosrib left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review: fix/aicore-content-filter-fail-open

Verdict: ✅ No security issues


# Criterion Status Finding
S1 Tenant subdomain validation ➖ No tenant/subdomain parameters introduced
S2 URL construction (structured, not str.replace) ➖ No URL construction
S3 Credential emptiness checks ➖ No credential fields read
S4 JWT tokens verified before trust ➖ No JWT handling
S5 No hardcoded credentials/secrets ✅ Only env var name literals and log message strings
S6 Sensitive data not logged ✅ Both new logger.warning calls use hardcoded reason strings — no request content, credentials, or PII in any log path
S7 No path traversal from external input ➖ No filesystem operations
S8 HTTP base URLs validated ➖ No HTTP requests constructed
S9 Multi-tenant cache isolation ➖ Module-level globals (_active_cfg, _strict_mode, _configured) are process-scoped by pre-existing design — not per-tenant, not changed by this PR
S10 New dependencies checked for CVEs ➖ No new dependencies
S11 No verify=False in HTTP calls ➖ No HTTP calls
S12 Audit log for mutating tenant operations ➖ No tenant-scoped mutations

✅ Things Done Well

  • Warning messages contain no request body, no credentials, no user input — only hardcoded literal strings, so there is no risk of accidentally surfacing sensitive prompt content into logs.
  • ContentFilteringNotConfiguredError message is similarly inert — it describes the SDK state, not the request.
  • The PR itself remediates CWE-636 (Not Failing Securely), moving the module from silent fail-open to an observable and optionally fail-closed posture.

@ricardosrib
ricardosrib force-pushed the fix/aicore-content-filter-fail-open branch from 9f656a2 to 561ff50 Compare November 11, 2026 17:28
@ricardosrib
ricardosrib merged commit 8f0174f into main Nov 11, 2026
13 of 14 checks passed
@ricardosrib
ricardosrib deleted the fix/aicore-content-filter-fail-open branch November 11, 2026 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants